package com.cictec.middleware.gps.service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cictec.middleware.commons.cache.ecache.EHCacheUtils;
import com.cictec.middleware.commons.utils.Constants;
import com.cictec.middleware.commons.utils.PMSUtils;
import com.cictec.middleware.commons.utils.ZoneUtils;
import com.cictec.middleware.core.entity.BusLine;
import com.cictec.middleware.core.entity.BusLineMapPoint;
import com.cictec.middleware.core.entity.BusLineStation;
import com.cictec.middleware.core.entity.StandbyZone;
import com.cictec.middleware.core.entity.pojo.BaseBusLineInfo;
import com.cictec.middleware.feign.dc.MiddlewareDcLineServiceFeign;
import com.cictec.middleware.gps.pojo.BusLineInfo;
import com.vividsolutions.jts.geom.Geometry;

import net.sf.ehcache.Cache;

/**
 * 车辆线路、站点服务
 * 
 * @author ql
 *
 */
@Service
public class BusLineService {

	public static Logger logger = LoggerFactory.getLogger(BusLineService.class);

	@Autowired
	private BusLineMapPointService busLineMapPointService;
	@Autowired
	private BusLineStandbyService busLineStandbyService;
	@Autowired
	private BusLineStataionService busLineStataionService;

	/**
	 * 线路集合 key--> lineUuid 设备线路号
	 */
	// private ConcurrentMap<Integer, BusLine> lineMap = new ConcurrentHashMap<Integer, BusLine>();
//	private Map<Integer, BusLine> lineMap = new HashMap<Integer, BusLine>();
	private static String LINE_CACHE = "bus-line"; 		  			// 线路

	@Autowired
	private MiddlewareDcLineServiceFeign middlewareDcLineServiceFeign;
	
	/**
	 * 加载全部线路信息
	 *   由于存在多个数据库服务，所有这里默认加载所有的，按照区域编码区分
	 */
	public void loadBusLineInfo() {
		
		List<BusLineInfo> lineInfolist = new ArrayList<BusLineInfo>();
		List<BaseBusLineInfo> list = middlewareDcLineServiceFeign.getListBusLineInfos();
		lineInfolist.addAll(initBusLineGeometry(list));
		
		for (BusLineInfo busLineInfo : lineInfolist) {
			EHCacheUtils.setValue(LINE_CACHE, busLineInfo.getBusLine().getLineUuid(), busLineInfo);
		}
	}
	
	/**
	 * 加载线路信息
	 * @param lineUuid	
	 */
	public void loadBusLineInfo(String lineUuid) {
		
		BaseBusLineInfo baseBusLineInfo = middlewareDcLineServiceFeign.getListBusLineInfo(lineUuid);
		BusLineInfo busLineInfo = initBusLineInfo(baseBusLineInfo);
	
		EHCacheUtils.setValue(LINE_CACHE, lineUuid, busLineInfo);
	}
	
	private List<BusLineInfo> initBusLineGeometry(List<BaseBusLineInfo> baseBusLineInfoList){
		List<BusLineInfo> list = new ArrayList<BusLineInfo>();
		for (BaseBusLineInfo baseBusLineInfo : baseBusLineInfoList) {
			BusLineInfo info = initBusLineInfo(baseBusLineInfo);
			list.add(info);
		}
		return list;
	}
	
	private BusLineInfo initBusLineInfo(BaseBusLineInfo baseBusLineInfo){
		BusLineInfo info = new BusLineInfo(baseBusLineInfo.getBusLine(), baseBusLineInfo.getBusLineIds(),
				baseBusLineInfo.getStandbyZones(), baseBusLineInfo.getBusLineStationMap(),
				baseBusLineInfo.getBusLineMapPointsMap());
		info.setBusLineStationGeometry(busLineStataionService.initLineStationsGeometry(baseBusLineInfo.getBusLineStationMap()));
		info.setLineStandbyZonesGeometry(busLineStandbyService.initLineStandbyGeometry(baseBusLineInfo.getStandbyZones()));
		info.setBusLineMapPointsGeometry(busLineMapPointService.initLineMapPointGeometry(baseBusLineInfo.getBusLineMapPointsMap()));
		return info;
	}
	
	
	public BusLineInfo getBusLineInfo(String lineUuid){
		return EHCacheUtils.getValue(LINE_CACHE, lineUuid);
	}
	

	/**
	 * 获取所有线路信息
	 * 
	 * @return
	 */
	public List<BusLine> getAllLines() {
		List<BusLine> lineList = new ArrayList<BusLine>();
		List<String> keys = EHCacheUtils.getCache(LINE_CACHE).getKeys();
		for (String lineUuid : keys) {
			BusLineInfo busLineInfo = EHCacheUtils.getValue(LINE_CACHE, lineUuid);
			lineList.add(busLineInfo.getBusLine());
		}
		return lineList;
	}

	/**
	 * 根据设备线路号 查询线路信息
	 * 
	 * @param lineId
	 * @return
	 */
	public BusLine getLineByDeivceLineId(int lineId) {
		BusLine busLine = null;

		Cache cache = EHCacheUtils.getCache(LINE_CACHE);
		if(cache == null){
//			loadBusLineInfo();
		}
		loadBusLineInfo("359723d22ccc48d18560");
		
		List<String> keys = EHCacheUtils.getCache(LINE_CACHE).getKeys();
		for (String lineUuid : keys) {
			BusLineInfo busLineInfo = EHCacheUtils.getValue(LINE_CACHE, lineUuid);
			if(busLineInfo.getBusLineIds().contains(lineId)){
				busLine = busLineInfo.getBusLine();
				break;
			}
		}
		
		return busLine;
	}
	
	/**
	 * 根据设备线路号 查询线路信息
	 * 
	 * @param lineId
	 * @return
	 */
	public BusLine getLineByDeivceLineId(String lineId) {
		return getLineByDeivceLineId(Integer.parseInt(lineId));
	}


	/**
	 * 根据lineUuid查询线路信息
	 * 
	 * @param lineUuid
	 * @return
	 */
	public BusLine getLineByLineUuid(String lineUuid) {

		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		if(busLineInfo == null){
			return null;
		}
		return busLineInfo.getBusLine();

	}

	/**
	 * 【缓存】
	 * 
	 * @param lineUuid
	 * @return
	 */
	public List<StandbyZone> getStandbyZones(String lineUuid) {
		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		if(busLineInfo == null){
			return new ArrayList<StandbyZone>();
		}
		return busLineInfo.getStandbyZones();
	}

	/**
	 * 根据位置信息获取待发区，如果没有返回null，表示位置不再待发区
	 * 
	 * @param lineUuid
	 * @param lat
	 * @param lng
	 * @return
	 */
	public StandbyZone getStandbyZoneByPosition(String lineUuid, String lat, String lng) {
		return getStandbyZoneByPosition(lineUuid, Double.parseDouble(lat), Double.parseDouble(lng));
	}

	/**
	 * 根据位置信息获取待发区，如果没有返回null，表示位置不再待发区
	 * 
	 * @param lineUuid
	 * @param lat
	 * @param lng
	 * @return
	 */
	public StandbyZone getStandbyZoneByPosition(String lineUuid, double lat, double lng) {
		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		return busLineStandbyService.getStandbyZoneByPosition(busLineInfo, lat, lng);
	}

	/**
	 * 是否在待发区
	 * 
	 * @param lineUuid
	 * @param lat
	 * @param lng
	 * @return
	 */
	public boolean isInStandbyZone(String lineUuid, String lat, String lng) {
		return getStandbyZoneByPosition(lineUuid, Double.parseDouble(lat), Double.parseDouble(lng)) == null ? false : true;
	}

	/**
	 * 判定GPS点是否偏离线路
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public boolean isDeviate(String lineUuid, String lineType, Double lat, Double lng) {
		return isDeviate(lineUuid, lineType, String.valueOf(lat), String.valueOf(lng));
	}

	/**
	 * 判定GPS点是否偏离线路
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public boolean isDeviate(String lineUuid, String lineType, String lat, String lng) {
		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		return !ZoneUtils.isInLineStringGeometry(busLineInfo.getBusLineMapPointsGeometry().get(lineType), lat, lng);
	}
	

	/**
	 * 【缓存】获取线路上所有站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 *            如果为null，取全部线路站点 先 上行、后下行排序
	 * @return
	 */
	public List<BusLineStation> getLineStations(String lineUuid, String lineType) {
		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		if(busLineInfo == null){
			return new ArrayList<BusLineStation>();
		}
		return busLineInfo.getBusLineStations(lineType);
	}


	/**
	 * 【缓存】获取线路的第一个站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public BusLineStation getLineStationFirst(String lineUuid, String lineType) {
		List<BusLineStation> busLineStations = getLineStations(lineUuid, lineType);
		if (busLineStations.size() > 0) {
			return busLineStations.get(0);
		} else {
			return null;
		}
	}

	/**
	 * 【缓存】获取指定线路线路类型最后一个站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @return
	 */
	public BusLineStation getLineStationLast(String lineUuid, String lineType) {
		List<BusLineStation> busLineStations = getLineStations(lineUuid, lineType);
		if (busLineStations.size() > 0) {
			return busLineStations.get(busLineStations.size() - 1);
		} else {
			return null;
		}
	}

	/**
	 * 根据 线路uuid， 上传数据站点编号，查询当前站点（线路上下行）信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param stationSeq
	 * @return
	 */
	public BusLineStation getLineStationByStationSeq(String lineUuid, String lineType, int stationSeq) {
		return getLineStationByStationSeq(lineUuid, lineType, String.valueOf(stationSeq));
	}

	public BusLineStation getLineStationByStationSeq(String lineUuid, String lineType, String stationSeq) {
		List<BusLineStation> busLineStations = getLineStations(lineUuid, lineType);
		return busLineStataionService.getLineStationByStationSeq(busLineStations, Integer.parseInt(stationSeq));
	}

	/**
	 * 根据 线路uuid， 上传数据站点编号，查询当前站点（线路上下行）信息 【注意】这里按照 线路站点 数组 的index值
	 * 
	 * @param lineUuid
	 * @param stationCode
	 *            【上传数据】站点编号
	 * @return
	 */
	public BusLineStation getLineStationByStationSeq(String lineUuid, int stationCode) {

		List<BusLineStation> upBusLineStations = getLineStations(lineUuid, "1");
		List<BusLineStation> downBusLineStations = getLineStations(lineUuid, "2");

		List<BusLineStation> stationList = new ArrayList<BusLineStation>();
		stationList.addAll(upBusLineStations);
		stationList.addAll(downBusLineStations);

		BusLineStation station = null;
		if (stationList.size() != 0 && stationCode > stationList.size()) {
			station = stationList.get(stationCode - 1);
		}
		return station;
	}

	/**
	 * 根据位置信息（坐标）获取站点信息（gps点不再站点围栏内，根据该点，倒序取经过的第一个站点，即为该站点的出站状态【出站状态】）
	 * 
	 * @return
	 */
	public BusLineStation getNearstBusLineStation(String lineUuid, String lineType, String latitude, String longitude) {

		BusLineStation lineStation = null;
		List<BusLineMapPoint> points = getBusLineMapPoints(lineUuid, lineType);
		BusLineMapPoint point = busLineMapPointService.getNearstPoint(points, latitude, longitude);
		int nearstPointIndex = point.getMlSequence() - 1; // 真是游标
		for (int i = nearstPointIndex; i < points.size(); i--) {

			// 找到最近的一个刚出的站序
			if (points.get(i).getMlWhichstop() > 0) {
				int tmpSeq = points.get(i).getMlWhichstop();
				lineStation = getLineStationByStationSeq(lineUuid, lineType, tmpSeq);
				break;
			}
		}
		return lineStation;
	}

	public List<BusLineMapPoint> getBusLineMapPoints(String lineUuid, String lineType) {
		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		if(busLineInfo == null){
			return new ArrayList<BusLineMapPoint>();
		}
		return busLineInfo.getBusLineMapPoints(lineType);
	}

	/**
	 * 判定当前站是否是第{x}站 <br>
	 * 根据线路类型判定，如果是单向、双向发车，lineType不为null的时候，取指定上下行总的站点排序
	 * 
	 * @param lineUuid
	 *            线路UUID
	 * @param lineType
	 *            线路类型
	 * @param stationSequence
	 *            当前站站序
	 * @param stationIndex
	 *            是否是第x站, x>0整数第几站, x<0倒数第几站, x=0返回false,不做判定
	 * @return
	 */
	public boolean isLineStationByIndex(String lineUuid, String lineType, int stationSequence, int stationIndex) {
		BusLineStation ls = getLineStationByStationSeq(lineUuid, lineType, stationSequence);

		return stationSequence == ls.getLsSequence();
	}

	public boolean isLastLineStation(String lineUuid, String lineType, String stationSequence) {
		BusLineStation ls = getLineStationLast(lineUuid, lineType);
		if (ls.getLsSequence() == Integer.parseInt(stationSequence)) {
			return true;
		}
		return false;
	}

	/**
	 * 根据位置信息（坐标）获取站点信息
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public List<BusLineStation> getLineStationByPosition(String lineUuid, String lineType, String lat, String lng) {
		return getLineStationByPosition(lineUuid, lineType, Double.parseDouble(lat), Double.parseDouble(lng));
	}

	/**
	 * 根据位置信息（坐标）获取站点信息（如果存储，则点落在给站点围栏内【进站状态】）
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param lat
	 * @param lng
	 * @return
	 */
	public List<BusLineStation> getLineStationByPosition(String lineUuid, String lineType, double lat, double lng) {
		
		BusLineInfo busLineInfo = getBusLineInfo(lineUuid);
		if(busLineInfo == null){
			return new ArrayList<BusLineStation>();
		}
		
		List<BusLineStation> result = new ArrayList<BusLineStation>();
		List<BusLineStation> stations =  busLineInfo.getBusLineStations(lineType);
		List<Geometry>  stationGeometryList = busLineInfo.getBusLineStationGeometry().get(lineType);
		
		Geometry pointGeometry = ZoneUtils.getPointGeometry(lat, lng);
		for (int i = 0; i < stationGeometryList.size(); i++) {
			Geometry geometry = stationGeometryList.get(i);
			if (geometry != null && geometry.contains(pointGeometry)) {
				result.add(stations.get(i));
			}
		}
		return result;
	}

	/**
	 * 相对距离计算（总线路相对距离）
	 * 
	 * @param mapLines
	 * @param latitude
	 * @param longitude
	 * @param stationSeq
	 *            (站点信息可能导致问题，详见方法说明)，所以次值可设置null
	 * @return
	 */
	public double caculateRealtiveDistanceByLine(String lineUuid, String lineType, String latitude, String longitude,
			Integer stationSeq) {

		// 计算车辆的相对位置
		double rate = 0;
		List<BusLineMapPoint> busLineMapPoints = getBusLineMapPoints(lineUuid, lineType);

		List<BusLineMapPoint> nearPoints = busLineMapPointService.getNearstPoints(busLineMapPoints, latitude, longitude, stationSeq);
		try {
			if (busLineMapPoints.size() > 0) {
				double lineLength = busLineMapPoints.get(busLineMapPoints.size() - 1).getMlDistance();
				double relativeValue = ZoneUtils.relativeValue(nearPoints, latitude, longitude, lineLength);
				rate = new BigDecimal(relativeValue).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
			}
		} catch (Exception e) {
			e.printStackTrace();
			logger.error(e.getMessage());
		}
		return rate;
	}

	/**
	 * 相对距离计算（站点间相对距离）
	 * 
	 * @param lineUuid
	 * @param lineType
	 * @param latitude
	 * @param longitude
	 * @param lineStationSeq
	 * @param enterOutStatus
	 * @return
	 */
	public double caculateRealtiveDistanceByStation(String lineUuid, String lineType, String latitude, String longitude, String lineStationSeq, String enterOutStatus) {
		// 计算车辆的相对位置
		double rate = 0;
		if (PMSUtils.isEmpty(lineStationSeq)) {
			return rate;
		}
		if (enterOutStatus.equals(Constants.VAL_ENTER_OUT_SATION_ENTER)) {
			// 进站状态，相对位置都为0
			rate = 0;
		} else {
			if (!PMSUtils.isEmpty(lineStationSeq)) {
				int orgStationSeq = Integer.parseInt(lineStationSeq) - 1; // 原来出站站序
				if (orgStationSeq < 1) {
					orgStationSeq = 1;
				}

				List<BusLineMapPoint> busLineMapPoints = getBusLineMapPoints(lineUuid, lineType);
				BusLineMapPoint startStationPoint = busLineMapPointService.getBusLineMapPoint(busLineMapPoints, orgStationSeq);
				BusLineMapPoint endStaionPoint = busLineMapPointService.getBusLineMapPoint(busLineMapPoints, orgStationSeq + 1);
				if (endStaionPoint == null) {
					return rate;
				}

				List<BusLineMapPoint> nearPoints = busLineMapPointService.getBusLineMapPoint(busLineMapPoints, orgStationSeq, orgStationSeq + 1);
				if (nearPoints.size() > 0) {
					double startPointDistance = startStationPoint.getMlDistance();
					List<BusLineMapPoint> newPoints = new ArrayList<BusLineMapPoint>();
					
					for (BusLineMapPoint busLineMapPoint : nearPoints) {
						BusLineMapPoint point = new BusLineMapPoint();
						BeanUtils.copyProperties(busLineMapPoint, point);
						point.setMlDistance(point.getMlDistance() - startPointDistance);
//						System.out.println(point);
						newPoints.add(point);
					}
					
					double lineLength = endStaionPoint.getMlDistance() - startStationPoint.getMlDistance();
					double relativeValue = ZoneUtils.relativeValue(newPoints, latitude, longitude, lineLength);
					rate = new BigDecimal(relativeValue).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
					
//					double lineLength = endStaionPoint.getMlDistance() - startStationPoint.getMlDistance();
//					double relativeValue = ZoneUtils.relativeValue(nearPoints, latitude, longitude, lineLength);
//					rate = new BigDecimal(relativeValue).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue();
				}
			}
		}
		return rate;
	}

	/** 获取发车类型（0单向 ，1双向，2环线） */
	public Integer getLineBfType(String lineUuid) {
		BusLine busLine = getLineByLineUuid(lineUuid);
		if (busLine != null) {
			return busLine.getLineBfType();
		}
		return null;
	}

}
